package com.spider.im.chat.server;

import cn.hutool.json.JSONUtil;
import com.google.protobuf.ByteString;
import com.spider.im.chat.message.MessageHandlerContext;
import com.spider.im.chat.message.MessageStrategy;
import com.spider.im.chat.proto.ChatProto;
import com.spider.im.chat.req.ChatMessage;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.websocketx.BinaryWebSocketFrame;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import io.netty.handler.timeout.IdleState;
import io.netty.handler.timeout.IdleStateEvent;
import lombok.extern.slf4j.Slf4j;

import java.io.IOException;
import java.util.concurrent.atomic.AtomicInteger;

@Slf4j
public class IMServerHandler extends SimpleChannelInboundHandler<ChatProto.MessageWrapper> {

    private final MessageHandlerContext messageHandlerContext;
    private final AtomicInteger connectionsCount;

    public IMServerHandler(MessageHandlerContext messageHandlerContext, AtomicInteger connectionsCount) {
        this.messageHandlerContext = messageHandlerContext;
        this.connectionsCount = connectionsCount;
    }


    @Override
    public void channelActive(ChannelHandlerContext ctx) throws IOException {
        log.info("新客户端连接：{}" , ctx.channel().remoteAddress());
//        String requestJson = "Welcome to the server!";
//        ChatProto.MessageWrapper wrapper = getMessageWrapper(true,requestJson);
////        ctx.writeAndFlush(new BinaryWebSocketFrame(Unpooled.wrappedBuffer(wrapper.toByteArray())));
////        ctx.writeAndFlush(wrapper);
//        // 发送响应消息
//        ByteBuf buffer = ctx.alloc().buffer();
//        CodedOutputStream outputStream = CodedOutputStream.newInstance(buffer.nioBuffer());
//        wrapper.writeTo(outputStream);
//        outputStream.flush(); // 确保所有数据写入到 ByteBuf 中
//        ctx.channel().writeAndFlush(new BinaryWebSocketFrame(buffer));
    }
    /**
     * 构建消息包装
     *
     * @return
     */
    private static ChatProto.MessageWrapper getMessageWrapper(boolean success, String message) {
        ChatProto.Response response = ChatProto.Response.newBuilder()
                .setSuccess(success)
                .setMessage(message)
                .build();
        return ChatProto.MessageWrapper.newBuilder()
                .setType(ChatProto.MessageType.LOGIN)
                .setPayload(response.toByteString())
                .build();
    }


    @Override
    protected void channelRead0(ChannelHandlerContext ctx, ChatProto.MessageWrapper msg) throws IOException {
//        log.info("Received Protobuf message: " + msg.getPayload());
//        ChatProto.MessageType type = msg.getType();
//        MessageStrategy<?> strategy = messageHandlerContext.getStrategy(type);
//        strategy.handle(ctx, msg.getPayload());
        ChatProto.MessageWrapper wrapper = getMessageWrapper(true,"Welcome to the server!");

        // 将 protobuf 消息序列化为 ByteString
        ByteString byteString = wrapper.toByteString();
        // 将 ByteString 转换为 ByteBuf
        ByteBuf buffer = ctx.alloc().buffer(byteString.size());
        buffer.writeBytes(byteString.asReadOnlyByteBuffer());
        // 发送响应消息
        ctx.channel().writeAndFlush(new BinaryWebSocketFrame(buffer));
//        ctx.channel().writeAndFlush(new BinaryWebSocketFrame(Unpooled.wrappedBuffer(wrapper.toByteArray())));
    }


    @Override
    public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
        super.handlerAdded(ctx);
        connectionsCount.incrementAndGet();
        log.info("Client connected. Total connections: {}" , connectionsCount.get());
    }

    @Override
    public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
        super.handlerRemoved(ctx);
        connectionsCount.decrementAndGet();
        log.info("Client disconnected. Total connections: {}" , connectionsCount.get());
    }

//
//    @Override
//    protected void channelRead0(ChannelHandlerContext ctx, TextWebSocketFrame msg) throws Exception {
//        // 检查握手是否成功
//        if (!ctx.channel().isActive() || !ctx.channel().isOpen()) {
//            log.warn("Handshake not completed or connection is closed. Closing the channel.");
//            ctx.close();
//            return;
//        }
//        String requestJson = msg.text();
//        log.info(String.format("%s received %s", ctx.channel(), requestJson));
//
////        messageService.processRequest(requestJson, ctx.channel());
//
//            ctx.channel().writeAndFlush(new TextWebSocketFrame(requestJson));
//
//    }
//
//@Override
//protected void channelRead0(ChannelHandlerContext ctx, Object msg) throws Exception {
//    log.info("Received message: {}" , msg);
//    if (msg instanceof TextWebSocketFrame) {
//        handleJson(ctx, (TextWebSocketFrame) msg);
//    } else if (msg instanceof BinaryWebSocketFrame) {
//        handleBinaryFrame(ctx, (BinaryWebSocketFrame) msg);
//    }
//
//}

    private void handleJson(ChannelHandlerContext ctx, TextWebSocketFrame frame) throws IOException {
       String text = frame.text();
        if (!text.startsWith("{")) {
            // 判断是否为JSON格式
            return;
        }
        //@TODO 格式有问题需要重新定义json格式

        log.info("Received JSON message: " + text);
        ChatMessage chatMessage = JSONUtil.toBean(text, ChatMessage.class);

//        ChatProto.MessageType type = msg.getType();
//        MessageStrategy<?> strategy = messageHandlerContext.getStrategy(type);
        ctx.channel().writeAndFlush(text);
    }

    private void handleProtobuf(ChannelHandlerContext ctx,  byte[] bytes) throws IOException {
        ChatProto.MessageWrapper msg = ChatProto.MessageWrapper.parseFrom(bytes);
        log.info("Received Protobuf message: " + msg.getPayload());
        ChatProto.MessageType type = msg.getType();
        MessageStrategy<?> strategy = messageHandlerContext.getStrategy(type);
        strategy.handle(ctx, msg.getPayload());
    }
    private void handleBinaryFrame(ChannelHandlerContext ctx, BinaryWebSocketFrame frame) throws IOException {
        ByteBuf byteBuf = frame.content();
        byte[] bytes = new byte[byteBuf.readableBytes()];
        byteBuf.readBytes(bytes);
        handleProtobuf(ctx, bytes);
    }
    /**
     * 当用户事件触发时调用此方法
     * 主要用于处理IdleStateEvent事件，以确定何时通道由于不活动而需要关闭
     *
     * @param ctx 通道处理上下文，提供了访问通道、管道等信息的能力
     * @param evt 触发的事件对象，本方法中主要关注IdleStateEvent
     * @throws Exception 如果处理事件时发生错误，可以抛出异常
     */
    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
        // 判断事件是否为IdleStateEvent类型
        if (evt instanceof IdleStateEvent idleStateEvent) {
            try {
                // 判断是否为 ALL_IDLE 状态
                if (idleStateEvent.state() == IdleState.ALL_IDLE) {
                    // 如果是ALL_IDLE状态，记录警告日志并关闭连接
                    log.warn("Closing connection due to inactivity - channelId: {}, state: {}",
                            ctx.channel().id(), idleStateEvent.state());
                    ctx.close(); // 关闭连接
                } else {
                    // 如果不是ALL_IDLE状态，调用方法处理其他状态的事件
                    handleNonIdleEvent(ctx, idleStateEvent);
                }
            } catch (Exception e) {
                // 异常处理，记录错误日志
                log.error("An error occurred while handling IdleStateEvent for channel {}: {}",
                        ctx.channel().id(), e.getMessage(), e);
            }
        } else {
            // 如果事件不是IdleStateEvent类型，调用父类方法处理
            super.userEventTriggered(ctx, evt);
        }
    }

    private void handleNonIdleEvent(ChannelHandlerContext ctx, IdleStateEvent idleStateEvent) {
        try {
            log.debug("Handling non-ALL_IDLE event - channelId: {}, state: {}",
                    ctx.channel().id(), idleStateEvent.state());
            super.userEventTriggered(ctx, idleStateEvent);
        } catch (Exception e) {
            log.error("An error occurred while handling non-ALL_IDLE event for channel {}: {}",
                    ctx.channel().id(), e.getMessage(), e);
        }
    }


    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {

        log.error("Exception occurred during handshake or communication: ", cause);
        ctx.close();
    }

}
